import subprocess
import sys
import shlex
from optparse import OptionParser
import lib.common
import lib.constants
import lib.functions
APP_TITLE = "State Report"

parser = OptionParser()
parser.add_option("-n","--node", dest="node",help="Specify the Node to want to report state on")
parser.add_option("-g","--group", dest="group",help="Specify the Node to want to report state on")
parser.add_option("-e","--enforce",action="store_true", dest="enforce",help="Specify the Node to want to report state on")

(options, args) = parser.parse_args()

lib.functions.banner(lib.constants.TITLE + " v" + str(lib.constants.VERSION) + " -- " + APP_TITLE)
if not options.node and not options.group:
    print "Nothing specified -- Exiting"
    sys.exit(1)

if options.node and options.group:
    print "Both node and group specified, only one at a time is support -- Exiting"
    sys.exit(1)

if options.node and not lib.common.member_groups.has_key(options.node.lower()):
    print "Node not set to be managed in your config -- Exiting"
    sys.exit(1)


def process_state(node_name,enforce):
    depends_already_passed = []
    print "Node:", node_name
    final_state_success = True
    group_size = len(lib.common.member_groups[node_name.lower()])
    for (group_count,group) in enumerate(lib.common.member_groups[node_name.lower()]):
        print "Member of: '"+group+"' (" + str(group_count+1) + " of " + str(group_size) + ")"
        final_state_size = len(lib.common.final_state[group.lower()])
        
        for (final_state_count,state) in enumerate(lib.common.final_state[group.lower()]):
            print "\n*** Requested Final State: '"+state+"' (" + str(final_state_count+1) + " of " + str(final_state_size) + ") ***"
            depend_size = len(lib.common.full_depends[state])
            for (depend_count,depend) in enumerate(lib.common.full_depends[state]):
                if depend in depends_already_passed:
                    print " State:\t'"+state+"' has dependency: '" + depend + "'. That has already passed a dependency check... skipping. (" + str(depend_count+1) + " of " + str(depend_size) + ")"
                    continue
                if state==depend:
                    print " State:\t'"+state+"' is the final state. (" + str(depend_count+1) + " of " + str(depend_size) + ")"
                else:
                    print " State:\t'"+state+"' has dependency: '" + depend + "'. Checking to see if '"+depend+"' is in correct state. (" + str(depend_count+1) + " of " + str(depend_size) + ")"
                retry_count = 0
                retry_loop=True
                depend_passed = 0
                check_command_size = len(lib.common.checks[depend])
                while retry_loop and retry_count <= 1:
                    retry_count += 1
                    for (check_command_count,check_command) in enumerate(lib.common.checks[depend]):
                        connect_string = shlex.split(lib.common.nodes[node_name.lower()] + ' "' + check_command +'"')
                        try:
                            subprocess.check_call(connect_string,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                            print "\tPASS\t--\t(" + str(check_command_count+1) + " of " + str(check_command_size) + ")\t" + check_command
                            retry_loop=False
                            depend_passed+=1
                        except subprocess.CalledProcessError:
                            print "\tFAIL\t--\t(" + str(check_command_count+1) + " of " + str(check_command_size) + ")\t" + check_command
                            if enforce:
                                retry_loop = True
                                print "Attempting Remedy:"
                                for remedy_command in lib.common.remedys[depend]:
                                    connect_string = shlex.split(lib.common.nodes[node_name.lower()] + ' "' + remedy_command +'"')
                                    print " cmd:\t",remedy_command
                                    try:
                                        subprocess.check_call(connect_string,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                                    except:
                                        continue
                            else:
                                retry_loop = False
                if depend_passed == check_command_size:
                    if depend not in depends_already_passed:
                        depends_already_passed.append(depend)
                else:
                    final_state_success=False
    return final_state_success

if options.node:
    final_state_success = process_state(options.node.lower(),options.enforce)
    print ""
    if final_state_success:
        print "PASS: " + options.node + " is in it's correct Final State"
        sys.exit(0)
    else:
        print "FAIL: " + options.node + " is NOT in it's correct Final State"
        sys.exit(1)

if options.group and lib.common.groups.has_key(options.group.lower()):
    node_count = len(lib.common.groups[options.group.lower()])
    group_state_success = []
    for (index,node) in enumerate(lib.common.groups[options.group.lower()]):
        print "**** Processing Group: " + options.group + " -- Current Node: " + node + " (" +str(index+1) + " of " + str(node_count) + ") ****\n"
        group_state_success.append((node,process_state(node.lower(),options.enforce)))
        print ""
    lib.functions.banner("State Report for Group:" + options.group)
    for (node,state) in group_state_success:
        if state:
            print " " + node + "\tPASS"
        else:
            print " " + node + "\tFAIL"
    print ""
